/**
 * 
 */
package com.nari.heatshare.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.nari.baseinfo.dao.ICommunityDao;
import com.nari.baseinfo.dao.IHeatMeterDao;
import com.nari.baseinfo.model.IHeatMeter;
import com.nari.coreframe.service.GenericServiceImpl;
import com.nari.heatshare.dao.IHeatMeterDataGatherDao;
import com.nari.heatshare.dao.springjdbc.IHeatMeterDataJdbcDao;
import com.nari.heatshare.model.IHeatMeterDataGather;
import com.nari.heatshare.utils.MeterDataTransitionUtil;
import com.nari.heatshare.utils.queryvo.HeatMeterDataCustomizedQuery;
import com.nari.heatshare.utils.queryvo.HeatMeterDataRecordExtendQuery;
import com.nari.platform.date.CalendarUtils;
import com.nari.platform.model.PageCond;
import com.nari.platform.model.ResponseMsg;
import com.nari.platform.model.ResultWithPageCond;

/**
 * 
 * @author Xiaopeng
 * @date 2013-8-19
 */
public class HeatMeterDataGatherServiceImpl extends GenericServiceImpl<IHeatMeterDataGather, String>
		implements IHeatMeterDataGatherService {
	private IHeatMeterDao iHeatMeterDao;
	private ICommunityDao iCommunityDao;
	private IHeatMeterDataJdbcDao iHeatMeterDataJdbcDao;

	/**
	 * 分页查询热量表数据列表
	 * @param meterNo
	 * @param recordTime
	 * @param pageCond
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2014-6-23
	 */
	public ResultWithPageCond<IHeatMeterDataGather> queryMeterDataPage(String meterNo, 
			Date recordTime, PageCond pageCond) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.queryMeterDataPage(meterNo, recordTime, pageCond);
	}
	
	/**
	 * 分页查询热量表数据定制查询列表
	 * @param projectUID
	 * @param communityUID
	 * @param recordTimeStart
	 * @param recordTimeEnd
	 * @param pageCond
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2014-12-17
	 */
	public ResultWithPageCond<HeatMeterDataCustomizedQuery> queryCustomizedQueryPage(String projectUID, 
			String communityUID, Date recordTimeStart, Date recordTimeEnd,
			PageCond pageCond) throws Exception {
		return iHeatMeterDataJdbcDao.queryCustomizedQueryPage(projectUID, communityUID, recordTimeStart,
				recordTimeEnd, pageCond);
	}
	
	/**
	 * 通过定制查询列表查询与之关联的小区映射表
	 * @param customizedList
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2014-12-11
	 */
	public Map<String, String> queryReferCommunitysByCustomizedList(List<HeatMeterDataCustomizedQuery> 
			customizedList) throws Exception {
		List<String> communityIDList = null;
		if(customizedList!=null && customizedList.size()>0) {
			communityIDList = new ArrayList<String>();
			for(HeatMeterDataCustomizedQuery customizedQuery: customizedList) {
				communityIDList.add(customizedQuery.getCommunityUID());
			}
		}
		return iCommunityDao.queryIdNameMapByIDList(communityIDList);
	}
	
	/**
	 * 根据定制查询特征信息(所属小区、抄表时间)统计热量表列表数据个数
	 * @param communityUID
	 * @param recordTime
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2014-12-11
	 */
	public int countCustomizedHmDataList(String communityUID, Date recordTime) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.countCustomizedHmDataList(communityUID, recordTime);
	}
	
	/**
	 * 根据定制查询特征信息(所属小区、抄表时间)查询热量表数据列表
	 * @param communityUID
	 * @param recordTime
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2014-12-11
	 */
	public List<IHeatMeterDataGather> queryCustomizedHmDataList(String communityUID, 
			Date recordTime) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.queryCustomizedHmDataList(communityUID, recordTime);
	}
	
	/**
	 * 根据热量表数据列表查询数据记录对应的档案资料扩展信息
	 * @param heatMeterDateList
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2014-12-18
	 */
	public Map<String, HeatMeterDataRecordExtendQuery> queryHmdRecordExtend(List<IHeatMeterDataGather> 
			heatMeterDateList) throws Exception {
		StringBuffer meterDataUIDList = new StringBuffer("");
		if(heatMeterDateList!=null && heatMeterDateList.size()>0) {
			for(int index=0; index<heatMeterDateList.size(); index++) {
				meterDataUIDList.append(heatMeterDateList.get(index).getId());
				if(index < heatMeterDateList.size()-1) {
					meterDataUIDList.append(",");
				}
			}
		}
		return iHeatMeterDataJdbcDao.queryHmdRecordExtend(meterDataUIDList.toString());
	}
	
	/**
	 * 通过所属分摊域ID及抄表日期统计热量表数据的数量
	 * @param shareAreaUID 所属分摊域
	 * @param recordDate 抄表时间
	 * @param calculateType 热表计算关系
	 * 	说明：add:加		subs:减
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-9-8
	 */
	public int countMeterDatasByAreaUIDAndDate(String shareAreaUID, Date recordDate, 
			String calculateType) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.countMeterDatasByAreaUIDAndDate(shareAreaUID, recordDate, calculateType);
	}
	
	/**
	 * 通过热量表表号及抄表日期统计热量表数据的数量
	 * @param meterNo 热量表表号
	 * @param recordDate 抄表时间
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-9-8
	 */
	public int countMeterDatasByMeterNoAndDate(String meterNo, Date recordDate) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.countMeterDatasByMeterNoAndDate(meterNo, recordDate);
	}
	
	/**
	 * 根据分摊域分页查询所属热量表数据
	 * @param shareAreaUID 分摊域唯一标识(必须)
	 * @param meterNo 热量表表号(可选)
	 * @param pageCond
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-10-1
	 */
	public ResultWithPageCond<IHeatMeterDataGather> queryMeterDataPageByAreaUID(String shareAreaUID, 
			String meterNo, PageCond pageCond) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.queryMeterDataPageByAreaUID(shareAreaUID, meterNo, pageCond);
	}
	
	/**
	 * 根据热量表ID查询某个时间段内的热消耗量
	 * @param meterUID 热量表ID
	 * @param startDate 起始日期
	 * @param endDate 结束日期
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-10-9
	 */
	public double queryHeatConsumeByMeterUID(String meterUID, Date startDate, 
			Date endDate) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.queryHeatConsumeByMeterUID(meterUID, startDate, endDate);
	}
	
	/**
	 * 根据热量表表号、抄表日期查询历史数据
	 * @param meterNo 热量表表号
	 * @param recordTime 抄表日期
	 * @param dataLimit 取回历史数据的条数，若不限制，则取回所有历史数据
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-10-14
	 */
	public List<IHeatMeterDataGather> queryHistoryMeterData(String meterNo, 
			Date recordTime, Integer dataLimit) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.queryHistoryMeterData(meterNo, recordTime, dataLimit);
	}
	
	/**
	 * 新增热量表平滑数据(包括人工干预数据和系统自动平滑数据)
	 * @param meterNo 热量表表号
	 * @param recordTime 抄表时间
	 * @param sumHeat 累计热量
	 * @param sumHeatUnit 累计热量单位 1:MWh 2:kWh 3:Gj
	 * @return 返回平滑数据的ID
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-10-14
	 */
	public String saveTransitionMeterData(String meterNo, Date recordTime, 
			double sumHeat, Integer sumHeatUnit) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.saveTransitionMeterData(meterNo, recordTime, sumHeat, sumHeatUnit);
	}
	
	/**
	 * 自动平滑热量表数据
	 * @param shareAreaUID
	 * @param startDate
	 * @param endDate
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-10-15
	 */
	public ResponseMsg saveAutoTransitionMeterData(String shareAreaUID, Date startDate, 
			Date endDate) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		//热量表基本信息
		List<IHeatMeter> heatMeterList = iHeatMeterDao.queryMetersByBelongs(null, null, null, shareAreaUID);
		if(heatMeterList==null || heatMeterList.size()==0) {
			return ResponseMsg.getInstance(false, "缺少分摊域对应的热量表信息，数据无法平滑！");
		}
		for(IHeatMeter heatMeter: heatMeterList) {
			//热量表数据完整性校验 - 对应于分摊周期起始日期的热量表数据检查
			int startMeterDataNum = iHeatMeterDataGatherDao.countMeterDatasByMeterNoAndDate(heatMeter.getMeterNo(), startDate);
			if(startMeterDataNum <= 0) {
				//取前三次历史数据，作为数据平滑的依据
				List<IHeatMeterDataGather> historyMeterDatas = this.queryHistoryMeterData(heatMeter.getMeterNo(), startDate, 3);
				if(historyMeterDatas.size() < 2) {
					String msg = "截至日期到" + CalendarUtils.parseDateToString(startDate)
							+"，表号为" + heatMeter.getMeterNo() 
							+ "的热量表缺少足够的历史数据(至少2次以上)，数据无法平滑！";
					return ResponseMsg.getInstance(false, msg);
				}
				//平滑数据
				this.saveAutoGenerateTransitionData(historyMeterDatas, startDate);
			}
			//热量表数据完整性校验 - 对应于分摊周期结束日期的热量表数据检查
			int endMeterDataNum = iHeatMeterDataGatherDao.countMeterDatasByMeterNoAndDate(heatMeter.getMeterNo(), endDate);
			if(endMeterDataNum <= 0) {
				//取前三次历史数据，作为数据平滑的依据
				List<IHeatMeterDataGather> historyMeterDatas = this.queryHistoryMeterData(heatMeter.getMeterNo(), endDate, 3);
				if(historyMeterDatas.size() < 2) {
					String msg = "截至日期到" + CalendarUtils.parseDateToString(endDate)
							+"，表号为" + heatMeter.getMeterNo() 
							+ "的热量表缺少足够的历史数据(至少2次以上)，数据无法平滑！";
					return ResponseMsg.getInstance(false, msg);
				}
				//平滑数据
				this.saveAutoGenerateTransitionData(historyMeterDatas, endDate);
			}
		}
		return ResponseMsg.getInstance(true, "");
	}
	
	/**
	 * 依据历史数据，按照等差数列的方式生成平滑数据
	 * @param historyMeterDatas 历史数据(2=<历史数据<=3)
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-10-15
	 */
	private void saveAutoGenerateTransitionData(List<IHeatMeterDataGather> historyMeterDatas, 
			Date recordTime) throws Exception {
		//热量表表号
		String meterNo = historyMeterDatas.get(0).getMeterNo();
		//平滑累计热量，单位为MWh
		double transitionSumHeat = 0;
		Integer sumHeatUnit = 1; //热量单位 1:MWh 2:kWh 3:Gj
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		if(historyMeterDatas.size() == 2) {
			//每天的步阶值
			double perDayGradeValue = MeterDataTransitionUtil.calcGradeValueByDay(
					iHeatMeterDataGatherDao.formatSumHeatToMWh(historyMeterDatas.get(1)), 
					historyMeterDatas.get(1).getRecordTime(), 
					iHeatMeterDataGatherDao.formatSumHeatToMWh(historyMeterDatas.get(0)), 
					historyMeterDatas.get(0).getRecordTime());
			//计算平滑累计热量
			transitionSumHeat = MeterDataTransitionUtil.calcTransitionValue(
					iHeatMeterDataGatherDao.formatSumHeatToMWh(historyMeterDatas.get(1)),
					historyMeterDatas.get(1).getRecordTime(), 
					recordTime, perDayGradeValue);
		} else if(historyMeterDatas.size() == 3) {
			//每天的步阶值一
			double perDayGradeValue1 = MeterDataTransitionUtil.calcGradeValueByDay(
					iHeatMeterDataGatherDao.formatSumHeatToMWh(historyMeterDatas.get(1)), 
					historyMeterDatas.get(1).getRecordTime(), 
					iHeatMeterDataGatherDao.formatSumHeatToMWh(historyMeterDatas.get(0)), 
					historyMeterDatas.get(0).getRecordTime());
			//每天的步阶值二
			double perDayGradeValue2 = MeterDataTransitionUtil.calcGradeValueByDay(
					iHeatMeterDataGatherDao.formatSumHeatToMWh(historyMeterDatas.get(2)), 
					historyMeterDatas.get(2).getRecordTime(), 
					iHeatMeterDataGatherDao.formatSumHeatToMWh(historyMeterDatas.get(1)), 
					historyMeterDatas.get(1).getRecordTime());
			//取平均的每天步阶值
			BigDecimal perDayGradeValueSum = new BigDecimal(perDayGradeValue1)
					.add(new BigDecimal(perDayGradeValue2));
			double avgPerDayGradeValue = perDayGradeValueSum
					.divide(new BigDecimal("2"))
					.doubleValue();
			//计算平滑累计热量
			transitionSumHeat = MeterDataTransitionUtil.calcTransitionValue(
					iHeatMeterDataGatherDao.formatSumHeatToMWh(historyMeterDatas.get(2)),
					historyMeterDatas.get(1).getRecordTime(), 
					recordTime, avgPerDayGradeValue);
		}
		this.saveTransitionMeterData(meterNo, recordTime, transitionSumHeat, sumHeatUnit);
	}
	
	/**
	 * 新增或修改热量表数据
	 * 说明：若存在相同表号、相同抄表日期的热量表数据，则无法新增
	 * @param meterData
	 * @return
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2013-11-13
	 */
	public ResponseMsg saveOrUpdateMeterData(IHeatMeterDataGather meterData) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.saveOrUpdateMeterData(meterData);
	}
	
	/**
	 * 统计某一时段内热表的计量值
	 * 说明：若此时段内热表数据少于两条记录，则返回0
	 * @param meterNo
	 * @param startDate
	 * @param endDate
	 * @return 返回计量热量的热量单位为MWh
	 * @throws Exception
	 * @author Xiaopeng
	 * @date 2014-4-28
	 */
	public double calcMeterMeasureDataMWhByPeriod(String meterNo, Date startDate, 
			Date endDate) throws Exception {
		IHeatMeterDataGatherDao iHeatMeterDataGatherDao = (IHeatMeterDataGatherDao) this.getiGenericDao();
		return iHeatMeterDataGatherDao.calcMeterMeasureDataMWhByPeriod(meterNo, startDate, endDate);
	}

	/**
	 * @return the iHeatMeterDao
	 */
	public IHeatMeterDao getiHeatMeterDao() {
		return iHeatMeterDao;
	}

	/**
	 * @param iHeatMeterDao the iHeatMeterDao to set
	 */
	public void setiHeatMeterDao(IHeatMeterDao iHeatMeterDao) {
		this.iHeatMeterDao = iHeatMeterDao;
	}

	/**
	 * @return the iCommunityDao
	 */
	public ICommunityDao getiCommunityDao() {
		return iCommunityDao;
	}

	/**
	 * @param iCommunityDao the iCommunityDao to set
	 */
	public void setiCommunityDao(ICommunityDao iCommunityDao) {
		this.iCommunityDao = iCommunityDao;
	}

	/**
	 * @return the iHeatMeterDataJdbcDao
	 */
	public IHeatMeterDataJdbcDao getiHeatMeterDataJdbcDao() {
		return iHeatMeterDataJdbcDao;
	}

	/**
	 * @param iHeatMeterDataJdbcDao the iHeatMeterDataJdbcDao to set
	 */
	public void setiHeatMeterDataJdbcDao(IHeatMeterDataJdbcDao iHeatMeterDataJdbcDao) {
		this.iHeatMeterDataJdbcDao = iHeatMeterDataJdbcDao;
	}
	
}
